import 'dart:core';
import 'dart:io';
import 'dart:async';

import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter/foundation.dart';
import 'package:random_uint8list/random_uint8list.dart';
import 'package:collection/collection.dart';
import 'package:dart_ipify/dart_ipify.dart';

///网络监听：是否有连接网络
class ConnectivityUtils {

  static String? publicIPAddress;

  StreamSubscription? subscription;
  ConnectivityResult? connectivityResult;
  String? address;
  Function(String address)? onIPAddressCallback;
  Function(String address)? onPublicIPAddressCallback;

  void init() {
    subscription = Connectivity()
        .onConnectivityChanged
        .listen((ConnectivityResult result) {
      connectivityResult = result;
      if (result == ConnectivityResult.none) {
        //无网络
      } else if (result == ConnectivityResult.wifi ||
          result == ConnectivityResult.ethernet ||
          result == ConnectivityResult.mobile) {
        //有网络
        try {
          intranetIp().then((ret) {
            //存储ret.address;
            address = ret.address;
            if (onIPAddressCallback != null) {
              onIPAddressCallback!(ret.address);
            }
          });
          Ipify.ipv4().then((value) {
            publicIPAddress = value;
            if (onPublicIPAddressCallback != null) {
              onPublicIPAddressCallback!(value);
            }
          });
        } catch (e) {
          if (kDebugMode) {
            print(e);
          }
        }
      }
    });
  }

  void cancel() {
    subscription?.cancel();
  }
}

///获取ip地址，wifi和有线都能获取到 如果没有网络会抛异常
Future<InternetAddress> intranetIp({InternetAddress? type}) async {
  const len = 16;
  final token = randomUint8List(len);
  final dgSocket = await RawDatagramSocket.bind(type??InternetAddress.anyIPv4, 0);
  dgSocket.readEventsEnabled = true;
  dgSocket.broadcastEnabled = true;
  final ret = dgSocket.timeout(const Duration(milliseconds: 500), onTimeout: (sink) {
    sink.close();
  }).expand<InternetAddress>((event) {
    if (event == RawSocketEvent.read) {
      final dg = dgSocket.receive();
      if (dg != null &&
          dg.data.length == len &&
          ListEquality().equals(dg.data, token)) {
        dgSocket.close();
        return [dg.address];
      }
    }
    return [];
  }).first;

  dgSocket.send(token, InternetAddress("255.255.255.255"), dgSocket.port);
  return ret;
}